3.3 现代风格:TTK
ttk
是Tk 8.5版本开始加入的模块。在之前,我们学习的小控件外观看起来都很陈旧过时,编写的界面会比较丑陋。而ttk
模块的出现正是为了解决这个问题,它使小控件的外观更接近于系统平台所特定的外观,不仅如此,它还能支持主题的定制,使我们能更简便的改进界面的美观程度。
TTK的使用
如果是使用from tkinter import *
方式导包,则只需在其下增加from tkinter.ttk import *
即可应用ttk风格。使用ttk
模块后,小控件外观会产生差别。
from tkinter import *
# 增加如下导包语句即可
from tkinter.ttk import *
root = Tk()
root.geometry("300x300")
top = LabelFrame(root, text="Label")
top.pack(padx=8, pady=8)
Label(top, text="我是标签,哈哈").pack()
body = LabelFrame(root, text="Button")
body.pack(padx=8, pady=8)
Button(body, text="你点啊").pack()
bottom = LabelFrame(root, text="其他")
bottom.pack(padx=8, pady=8)
Checkbutton(bottom, text="唱歌").pack()
Checkbutton(bottom, text="跳舞").pack()
Checkbutton(bottom, text="健身").pack()
Scale(bottom, orient='horizonta', from_=0, to=100).pack()
root.mainloop()
如使用其他方式导包,则需指定ttk
模块控件
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
ttk.Label(root, text="标签").pack()
ttk.Button(root, text="点啊").pack()
root.mainloop()
ttk
仅支持11个原核心控件
- Button
- Checkbutton
- Entry
- Frame
- Label
- LabelFrame
- Menubutton
- PanedWindow
- Radiobutton
- Scale
- Scrollbar
TTK 新增控件
ttk
新增了6个控件,这里我们主要介绍4个重要的
- Combobox 输入框下拉选项菜单
- Progressbar 进度条控件
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
ttk.Label(root, text="编程语言").pack(side=tk.LEFT, padx=5, pady=5)
combo = ttk.Combobox(root, values=["Go", "Python", "Java", "C++"])
# 设置当前选中的项
combo.current(1)
combo.pack(side=tk.LEFT, padx=5, pady=5)
# 创建进度条控件
progress = ttk.Progressbar(root, mode='indeterminate', length=100)
progress.pack(pady=10, padx=10)
# 启动进度条控件
progress.start()
progress2 = ttk.Progressbar(root, mode='determinate', length=100)
progress2.pack(pady=10, padx=10)
progress2.start()
root.mainloop()
Progressbar
参数说明:
mode
有两个值可选。
"indeterminate"
表示来回反弹样式,"determinate"
表示步进样式
- Notebook 选项卡控件
import tkinter as tk
from tkinter.ttk import *
root = tk.Tk()
root.geometry("300x300")
notebook = Notebook(root)
page1 = tk.Frame(notebook, background="yellow")
Label(page1, text="这是 tab1 的界面").pack()
page2 = tk.Frame(notebook, background="pink")
Label(page2, text="这是 tab2 的界面").pack()
notebook.add(page1, text="Tab1")
notebook.add(page2, text="Tab2")
notebook.pack(fill=tk.BOTH, expand="yes")
root.mainloop()
- Treeview 树形控件
树形结构简单示例
import tkinter as tk
from tkinter import ttk
def item_select(event):
for select in tree.selection():
print(tree.item(select, "text"))
root = tk.Tk()
tree = ttk.Treeview(root, show='tree')
# 监听tree中item被选中的事件
tree.bind("<<TreeviewSelect>>", item_select)
# 第一个参数为父节点, 第二个为此项在父节点中的位置(父节点为空时,默认为根节点)
item1 = tree.insert("", 0, text="广东省")
# 在第一个节点中插入如下子节点
tree.insert(item1, 0, text="广州市")
tree.insert(item1, 1, text="深圳市")
item2 = tree.insert("", 1, text="湖北省")
tree.insert(item2, 0, text="武汉市")
tree.pack()
root.mainloop()
用 Treeview
制作表格
import tkinter as tk
from tkinter import ttk
def item_select(event):
for select in tree.selection():
print(tree.item(select, "values"))
def head_onclick(type):
print(type)
root = tk.Tk()
# show用于禁止列顶部标签。columns用于设置每一列的列标识字符串
tree = ttk.Treeview(root, show='headings', columns=['0', '1', '2'])
# 监听tree中item被选中的事件
tree.bind("<<TreeviewSelect>>", item_select)
# 设置表头名称
tree.heading(0, text='序号', command=lambda: head_onclick('序号'))
tree.heading(1, text='姓名', command=lambda: head_onclick('姓名'))
tree.heading(2, text='年龄', command=lambda: head_onclick('年龄'))
# 设置每列中元素的样式
tree.column(0, anchor='center')
tree.column(1, anchor='center')
tree.column(2, anchor='center')
# "end" 表示往父节点的最后一个位置插入
item1 = tree.insert("", "end", values=("1", "赵二", "19"))
item1 = tree.insert("", "end", values=("2", "张三", "20"))
item1 = tree.insert("", "end", values=("3", "李四", "22"))
item1 = tree.insert("", "end", values=("4", "王五", "18"))
tree.pack()
root.mainloop()
Treeview
参数说明:
show
用于禁止列顶部标签。有两个值,
'tree'
表示禁止每一列的顶部标签栏,'headings'
表示禁止首列显示。
设置主题与样式
在使用ttk控件时,会发现它的控件不支持
bg
、fg
、border
这样涉及样式的属性,这是因为它对外观样式进行了重新定义。
ttk
对外观样式的抽象共有三个级别
- 主题
- 样式
- 状态样式
主题的查询与切换
from tkinter import ttk
style = ttk.Style()
# 获取所有支持的主题
print(style.theme_names())
# 获取当前使用的主题
print(style.theme_use())
# 切换主题
style.theme_use("classic")
样式与控件状态样式的定制
在ttk
中,控件实际上是一个字符串,要改变控件样式,需要指定这个字符串名称,而不是类名,它们的对应关系如下
类名 | 控件样式名 |
---|---|
Button | TButton |
Checkbutton | TCheckbutton |
Combobox | TCombobox |
Entry | TEntry |
Frame | TFrame |
Label | TLabel |
LabelFrame | TLabelFrame |
Menubutton | TMenubutton |
Notebook | TNotebook |
PanedWindow | TPanedwindow |
Progressbar | Horizontal.TProgressbar或Vertical.TProgressbar |
Radiobutton | TRadiobutton |
Scale | Horizontal.TScale 或 Vertical.TScale |
Scrollbar | Horizontal.TScrollbar 或Vertical.TScrollbar |
Separator | TSeparator |
Sizegrip | TSizegrip |
Treeview | Treeview |
需要注意,在创建新样式时,应当定义newName.oldName
形式的名称
from tkinter import Tk
from tkinter import ttk
root = Tk()
style = ttk.Style()
# 定义一个全局样式作为默认样式("."表示此样式将应用于顶级窗口及其所有子元素)
style.configure('.', font='Arial 14', foreground='brown', background='yellow')
# 未指定样式时,使用全局默认样式
ttk.Label(root, text='我没有指定样式').pack()
# 定义一个名为danger的新样式(newName.oldName格式)
style.configure('danger.TButton', font='Times 12', foreground='red', padding=1)
ttk.Button(root, text='我使用danger样式', style='danger.TButton').pack()
# 为小控件的不同状态指定样式
style.map("new_state_style.TButton", foreground=[('pressed', 'red'), ('active', 'blue')])
ttk.Button(text="不同状态不同样式", style="new_state_style.TButton").pack()
# 覆盖Entry的当前主题(即使没有指定样式,也会受到主题更改的影响)
current_theme = style.theme_use()
style.theme_settings(current_theme,
{"TEntry": {
"configure": {"padding": 10},
"map": {"foreground": [("focus", "red")]}}})
ttk.Entry().pack()
root.mainloop()